﻿// Copyright (c) 2009 http://grommet.codeplex.com
// This source is subject to the Microsoft Public License.
// See http://www.opensource.org/licenses/ms-pl.html
// All other rights reserved.

using System;
using System.Text;

namespace Grommet.Ext
{
    public static class BigEndianConvert
    {
        public static bool ToBoolean(byte[] value, int startIndex)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }
            if (startIndex < 0 || startIndex > (value.Length - 1))
            {
                throw new ArgumentOutOfRangeException("startIndex", "Argument is out of range");
            }
            return (value[startIndex] != 0);
        }

        public static DateTime ToDateTime(byte[] value, int startIndex)
        {
            DateTime dt = new DateTime(
                BigEndianConvert.ToInt16(value, startIndex),
                value[startIndex+2],
                value[startIndex+3],
                value[startIndex+4],
                value[startIndex+5],
                value[startIndex+6],
                BigEndianConvert.ToInt16(value, startIndex+7)
                );
            return DateTime.SpecifyKind(dt, DateTimeKind.Utc);
        }

        public static short ToInt16(byte[] value, int startIndex)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }
            if (startIndex < 0 || startIndex > (value.Length - 2))
            {
                throw new ArgumentOutOfRangeException("startIndex", "Argument is out of range");
            }
            return (short)(value[startIndex] << 8 | value[startIndex + 1]);
        }

        public static ushort ToUInt16(byte[] value, int startIndex)
        {
            return (ushort)ToInt16(value, startIndex);
        }

        public static int ToInt32(byte[] value, int startIndex)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }
            if (startIndex < 0 || startIndex > (value.Length - 4))
            {
                throw new ArgumentOutOfRangeException("startIndex", "Argument is out of range");
            }
            return value[startIndex] << 24 | value[startIndex + 1] << 16 |
                value[startIndex+2] << 8 | value[startIndex + 3];
        }

        public static uint ToUInt32(byte[] value, int startIndex)
        {
            return (uint)ToInt32(value, startIndex);
        }

        public static long ToInt64(byte[] value, int startIndex)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }
            if (startIndex < 0 || startIndex > (value.Length - 8))
            {
                throw new ArgumentOutOfRangeException("startIndex", "Argument is out of range");
            }
            int high = (((value[startIndex + 0] << 0x18) | (value[startIndex + 1] << 0x10)) | (value[startIndex + 2] << 8)) | value[startIndex + 3];
            int low = (((value[startIndex + 4] << 0x18) | (value[startIndex + 5] << 0x10)) | (value[startIndex + 6] << 8)) | value[startIndex + 7];
            return (((long) ((ulong) low)) | (((long)high) << 0x20));

        }

        public static ulong ToUInt64(byte[] value, int startIndex)
        {
            return (ulong)ToInt64(value, startIndex);
        }

        public static byte[] GetBytes(DateTime value)
        {
            DateTime utc = value.ToUniversalTime();
            byte[] middle = new byte[] 
            {
                (byte)value.Month,
                (byte)value.Day,
                (byte)value.Hour,
                (byte)value.Minute,
                (byte)value.Second
            };

            return Microsoft.SPOT.Hardware.Utility.CombineArrays(GetBytes((ushort)utc.Year),
                Microsoft.SPOT.Hardware.Utility.CombineArrays(middle, GetBytes((ushort)utc.Millisecond)));
        }

        public static byte[] GetBytes(short value)
        {
            byte[] buffer = new byte[2];
            buffer[0] = (byte)(value >> 8);
            buffer[1] = (byte)value;
            return buffer;
        }

        public static byte[] GetBytes(ushort value)
        {
            return GetBytes((short)value);
        }

        public static byte[] GetBytes(int value)
        {
            byte[] buffer = new byte[4];
            buffer[0] = (byte)(value >> 24);
            buffer[1] = (byte)(value >> 16);
            buffer[2] = (byte)(value >> 8);
            buffer[3] = (byte)value;
            return buffer;
        }

        public static byte[] GetBytes(uint value)
        {
            return GetBytes((int)value);
        }

        public static byte[] GetBytes(long value)
        {
            byte[] buffer = new byte[8];
            buffer[0] = (byte)(value >> 56);
            buffer[1] = (byte)(value >> 48);
            buffer[2] = (byte)(value >> 40);
            buffer[3] = (byte)(value >> 32);
            buffer[4] = (byte)(value >> 24);
            buffer[5] = (byte)(value >> 16);
            buffer[6] = (byte)(value >> 8);
            buffer[7] = (byte)value;
            return buffer;
        }

        public static byte[] GetBytes(ulong value)
        {
            return GetBytes((long)value);
        }

        public static byte[] GetBytes(string value)
        {
            byte[] buffer = Encoding.UTF8.GetBytes(value);
            return Microsoft.SPOT.Hardware.Utility.CombineArrays(buffer, new byte[] { 0 });
        }
    }
}
